﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Net;
using System.Xml;
using System.Security.Cryptography;
using System.IO;
using System.Text.RegularExpressions;
using System.Threading;
using Newtonsoft.Json;

namespace TwitterImageDownloader
{
    public partial class Form1 : Form
    {
        delegate void AddImageHandler(Image image);//The delegate

        //Twitter consumer key and secret
        // make sure to change them with your own.
        private String key = "1IqSPvvzs6PYyO86lrzgAQ";
        private String secret = "6h7Neyribi4aIyyy9pyJyzTBE0pqZd0kdIGGpQgPg";

        /// <summary>
        /// Application Only authentication as described in https://dev.twitter.com/docs/auth/application-only-auth
        /// </summary>
        /// <returns>authentication key</returns>
        private string authenticate()
        {
            //html encode the key & secret
            String htmlEncodedKey = WebUtility.HtmlEncode(key);
            String htmlEncodedSecret = WebUtility.HtmlEncode(secret);
            
            //combine the keys
            String bearCredentials = htmlEncodedKey + ":" + htmlEncodedSecret;

            //base64 convert the combined keys
            String base64Credentials = Convert.ToBase64String(Encoding.UTF8.GetBytes(bearCredentials));
            
            //submit token request
            HttpWebRequest req = WebRequest.Create("https://api.twitter.com/oauth2/token") as HttpWebRequest;
            req.Method = "POST";
            req.Headers[HttpRequestHeader.Authorization] = "Basic " + base64Credentials; ;
            req.ContentType = "application/x-www-form-urlencoded;charset=UTF-8";
            byte[] data = System.Text.Encoding.UTF8.GetBytes("grant_type=client_credentials");
            
            // Set the ContentLength property of the WebRequest.
            req.ContentLength = data.Length;

            req.UserAgent = "CodeBetweenTheLines/1.0 (compatible; MSIE 6.0; Windows NT 5.2; .NET CLR 1.0.3705;)";

            string response = null;
            Stream dataStream = req.GetRequestStream();
            dataStream.Write(data, 0, data.Length);
            dataStream.Close();
            WebResponse res = req.GetResponse();           
            dataStream = res.GetResponseStream();
            StreamReader reader = new StreamReader(dataStream);
            response = reader.ReadToEnd();
            reader.Close();
            dataStream.Close();
            res.Close();

            JsonTextReader jReader = new JsonTextReader(new StringReader(response));
            while (jReader.Read())
            {
                if (jReader.Value != null)
                    Console.WriteLine("Token: {0}, Value: {1}", jReader.TokenType.ToString(), jReader.Value);
                switch (jReader.TokenType)
                {
                    case JsonToken.PropertyName:
                        if (jReader.Value.Equals("access_token"))
                        {
                            jReader.Read();
                            return jReader.Value.ToString();
                        }
                        else if (jReader.Value.Equals("token_type"))
                        {
                            jReader.Read();
                            if (jReader.Value.ToString() != "bearer") throw new Exception("invalid json token_type recieved.");
                        }
                        break;
                    default:
                        //throw new Exception("invalid json token recieved.");
                        break;
                }
            }
            return String.Empty;
        }

        public Form1()
        {
            InitializeComponent();
            listView1.View = View.LargeIcon;
            imageList1.ImageSize = new Size(150, 150);
            listView1.LargeImageList = this.imageList1;
        }

        private void button1_Click(object sender, EventArgs e)
        {
            Thread t = new Thread(new ThreadStart(getImages));
            t.Start();
        }

        private void getImages()
        {
            String authToken = authenticate();
            String userTimelineUrl = @"https://api.twitter.com/1.1/statuses/user_timeline.json?screen_name=" + tbScreenName.Text + @"&count=200&trim_user=1&exclude_replies=1&include_rts=0";

            //First lets get the users tweets
            WebClient webClient = new WebClient();
            //Add the Autorization token to the request Header
            webClient.Headers.Add("Authorization", "Bearer " + authToken);
            String userTimeLine = webClient.DownloadString(userTimelineUrl);
            string tweetID = "0";
            bool inUser = false;
            JsonTextReader jReader = new JsonTextReader(new StringReader(userTimeLine));
            while (jReader.Read())
            {
                if (jReader.Value != null)
                {
                    if (jReader.Value.Equals("expanded_url"))
                    {
                        jReader.Read();
                        //read the link                   
                        string link = jReader.Value.ToString();
                        try
                        {
                            var request = (HttpWebRequest)WebRequest.Create(link);
                            string imageURL = String.Empty;
                            using (var response = request.GetResponse() as HttpWebResponse)
                            {
                                using (StreamReader sr = new StreamReader(response.GetResponseStream()))
                                {
                                    List<ImgTag> images = GetImageTags(sr.ReadToEnd());
                                    sr.Close();
                                    foreach (ImgTag image in images)
                                    {

                                        if (link.StartsWith("http:/") && link.IndexOf("/photo/") > -1)
                                        {
                                            //For twitter.com look for class=large media-slideshow-image
                                            if (image.classAtt == "large media-slideshow-image")
                                            {
                                                imageURL = image.src;
                                            }
                                        }
                                        if (link.StartsWith("http://instagr.am") || link.StartsWith("http://instagram.com"))
                                        {
                                            //For instagram look for class="photo" for the image tag                                              
                                            if (image.classAtt == "photo")
                                            {
                                                imageURL = image.src;
                                            }

                                        }
                                    }
                                }
                            }
                            if (imageURL != String.Empty)
                            {
                                //found an  Image 
                                Image img = LoadImage(imageURL, tweetID);
                                listView1.Invoke(new AddImageHandler(ImageThread), new object[] { img });
                            }
                        }
                        catch (Exception ex)
                        {
                            //skip tweet
                            Console.WriteLine(ex.Message);
                        }
                    }

                    if (jReader.Value.Equals("id_str") && !jReader.Path.Contains("user"))
                    {
                        jReader.Read();
                        //read the link                   
                        tweetID = jReader.Value.ToString();
                    }
                }
            }

            MessageBox.Show("Done.");
        }

        private void ImageThread(Image img)
        {
            imageList1.Images.Add(img);
            ListViewItem item = new ListViewItem();
            item.ImageIndex = listView1.Items.Count + 1;
            listView1.Items.Add(item);
            listView1.Refresh();
        }

        private List<ImgTag> GetImageTags(String html)
        {
            List<ImgTag> imgTags = new List<ImgTag>();
            MatchCollection m1 = Regex.Matches(html, @"(<img.*?>.*?>)", RegexOptions.Singleline);
            foreach (Match m in m1)
            {
                string value = m.Groups[1].Value;
                ImgTag imgTag = new ImgTag();
                Match m2 = Regex.Match(value, @"src=\""(.*?)\""", RegexOptions.Singleline);
                if (m2.Success)
                {
                    imgTag.src = m2.Groups[1].Value;
                }
                m2 = Regex.Match(value, @"class=\""(.*?)\""", RegexOptions.Singleline);
                if (m2.Success)
                {
                    imgTag.classAtt = m2.Groups[1].Value;
                }
                imgTags.Add(imgTag);
            }
            return imgTags;
        }

        private class ImgTag
        {
            public String src = String.Empty;
            public String classAtt = String.Empty;
        }

        private Image LoadImage(string url, string tweetID)
        {
            System.IO.Directory.CreateDirectory(System.IO.Path.Combine(Environment.CurrentDirectory.ToString(), tbScreenName.Text));
            String fileLocation = System.IO.Path.Combine(Environment.CurrentDirectory.ToString(), tbScreenName.Text, tweetID + ".jpg");
            using (var wc = new System.Net.WebClient())
            {
                wc.DownloadFile(url, fileLocation);
            }
            Bitmap bmp = new Bitmap(fileLocation);

            return bmp;
        }
    }
}
